﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Collections;
using System.Threading;
using IWshRuntimeLibrary;
using Shell32;
using System.IO;


namespace InLAN
{
    public partial class Form_MainWindow : Form
    {
        public Form_MainWindow()
        {
            InitializeComponent();
        }

        #region MyCode

        #region GlobalVar
        ArrayList WokenPcs = new ArrayList();
        ArrayList OpenChatWindows = new ArrayList();

        Socket UdpServer;
        Socket UdpClient;

        IPEndPoint UdpServerIpEndPoint;
        IPEndPoint UdpClientIpEndPoint;
        EndPoint UdpEndPoint;

        Thread StartServer = null;
        Thread StartClient = null;

        public int PortNum = 13000;
        bool threadstop = false;

        byte[] tempbyte;
        string[] tempstring;

        #endregion GlobalVar

        #region UdpServerClient
        public void UdpServerFunc()
        {
            UdpServer = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            UdpServer.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
            UdpServerIpEndPoint = new IPEndPoint(IPAddress.Any, 9050);
            UdpEndPoint = (EndPoint)UdpServerIpEndPoint;
            try
            {
                UdpServer.Bind(UdpServerIpEndPoint);
            }
            catch (SocketException e)
            {
                MessageBox.Show("Cannot Bind...\n" + e.ToString());
            }

            tempbyte = new byte[100];
            tempstring = new string[6];
            int messagelength;

            while(threadstop)
            {
                messagelength = UdpServer.ReceiveFrom(tempbyte,SocketFlags.None, ref UdpEndPoint);
                tempstring = (Encoding.ASCII.GetString(tempbyte,0,messagelength)).Split(':');
                if (tempstring[0] == "BlueBall" && tempstring[2] != ipaddress_ipv4())
                {
                    add_to_arraylist(tempstring[1], tempstring[2], tempstring[3], tempstring[4]);
                    if (this.listBox_MainList.Items.Count != WokenPcs.Count)
                    {
                        this.listBox_MainList.Invoke(new MethodInvoker(delegate
                        {
                            this.listBox_MainList.Items.Clear();
                            foreach (PC_list x in WokenPcs)
                            {
                                this.listBox_MainList.Items.Add(x.ThisToString());
                            }
                        }));
                    }
                    clean_arraylist();
                    if (Convert.ToInt32(tempstring[5]) > PortNum)
                    {
                        PortNum = Convert.ToInt32(tempstring[5]);
                    }
                }

                if (tempstring[0] == "BlueBall [OpenChat]" && tempstring[2] != ipaddress_ipv4())
                {
                    Invoke(new MethodInvoker(delegate
                    {
                        Form_ChatWindow newchat = new Form_ChatWindow(tempstring[2], Convert.ToInt32(tempstring[5]), tempstring[4], false);
                        newchat.Text = "InLAN Chat Messenger: " + tempstring[4];
                        newchat.Visible = false;
                        OpenChatWindows.Add(newchat);
                        newchat.Show();
                        PortNum = PortNum + 1;
                    }));
                }
            }
            try
            {
                UdpServer.Dispose();
            }
            catch(SocketException e)
            {
                MessageBox.Show("Could not close server thread: " + e.ToString());
            }
        }

        public void UdpClientFunc()
        {
            string message;
            UdpClient = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            UdpClientIpEndPoint = new IPEndPoint(IPAddress.Broadcast, 9050);
            byte[] Bmessage = new byte[100];
            string pcname = Dns.GetHostName();
            UdpClient.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);
            Invoke(new MethodInvoker(delegate
            {
                this.toolStripStatusLabel_StatusMainWindow.Text = "Status: Connected";

            }));
            
            while (threadstop)
            {
                message = "BlueBall:" + pcname + ":" + ipaddress_ipv4() + ":Available:" + this.textBox_NickName.Text + ":" + PortNum.ToString() + ":";
                Bmessage = Encoding.ASCII.GetBytes(message);
                UdpClient.SendTo(Bmessage, Bmessage.Length,SocketFlags.None, UdpClientIpEndPoint);
                Thread.Sleep(400);
                
            }
            
            Invoke(new MethodInvoker(delegate
            {
                this.toolStripStatusLabel_StatusMainWindow.Text = "Status: Disconnected";
                this.disconnectToolStripMenuItem.Enabled = false;

            }));

            try
            {
                UdpClient.Dispose();
            }
            catch (SocketException e)
            {
                MessageBox.Show("Could not close client thread: " + e.ToString());
            }
        }
        #endregion UdpServerClient

        #region MscFunc

        public void CreateStartupFolderShortcut()
        {
            WshShellClass wshShell = new WshShellClass();
            IWshRuntimeLibrary.IWshShortcut shortcut;
            string startUpFolderPath = Environment.GetFolderPath(Environment.SpecialFolder.Startup);
            shortcut = (IWshRuntimeLibrary.IWshShortcut)wshShell.CreateShortcut(startUpFolderPath + "\\" + Application.ProductName + ".lnk");
            shortcut.TargetPath = Application.ExecutablePath;
            shortcut.WorkingDirectory = Application.StartupPath;
            shortcut.Description = "InLAN Chat Messenger";
            shortcut.Save();
        }

        public string GetShortcutTargetFile(string shortcutFilename)
        {
            string pathOnly = Path.GetDirectoryName(shortcutFilename);
            string filenameOnly = Path.GetFileName(shortcutFilename);

            Shell32.Shell shell = new Shell32.ShellClass();
            Shell32.Folder folder = shell.NameSpace(pathOnly);
            Shell32.FolderItem folderItem = folder.ParseName(filenameOnly);
            if (folderItem != null)
            {
                Shell32.ShellLinkObject link =
                  (Shell32.ShellLinkObject)folderItem.GetLink;
                return link.Path;
            }

            return String.Empty; // Not found
        }

        public void DeleteStartupFolderShortcuts(string targetExeName)
        {
            string startUpFolderPath =
              Environment.GetFolderPath(Environment.SpecialFolder.Startup);

            DirectoryInfo di = new DirectoryInfo(startUpFolderPath);
            FileInfo[] files = di.GetFiles("*.lnk");

            foreach (FileInfo fi in files)
            {
                string shortcutTargetFile = GetShortcutTargetFile(fi.FullName);

                if (shortcutTargetFile.EndsWith(targetExeName,
                      StringComparison.InvariantCultureIgnoreCase))
                {
                    System.IO.File.Delete(fi.FullName);
                }
            }
        }

        //public void StartUpProg()
        //{
        //    WshShell = new WshShellClass();
        //    IWshRuntimeLibrary.IWshShortcut MyShortcut;
        //    MyShortcut = (IWshRuntimeLibrary.IWshShortcut)WshShell.CreateShortcut(@"C:\Documents and Settings\All Users\Desktop\cLchecker.lnk");
        //    MyShortcut.TargetPath = <strong class="highlight">Application</strong>.ExecutablePath;
        //    MyShortcut.Description = "Launch cLchecker";
        //    MyShortcut.IconLocation = <strong class="highlight">Application</strong>.StartupPath + @"\cLchecker.ico";
        //    MyShortcut.Save();
        //}

        public void ThreadStop()
        {
            threadstop = true;
        }

        public void clean_arraylist()
        {
            DateTime nowtime = DateTime.Now;
            ArrayList RemoveList = new ArrayList();
            foreach (PC_list x in WokenPcs)
            {
                if ((nowtime.Subtract(x.time)).TotalSeconds > 7)
                {
                    RemoveList.Add(x);
                    this.listBox_MainList.Invoke(new MethodInvoker(delegate
                    {
                        this.listBox_MainList.Items.Remove(x.ThisToString());

                    }));
                }
            }
            foreach (PC_list x in RemoveList)
            {
                WokenPcs.Remove(x);

            }

        }

        public void add_to_arraylist(string PcName, string Ipadd, string status, string nickname)
        {
            if (ipaddress_ipv4() != Ipadd)
            {
                bool exists = true;
                DateTime addingtime = DateTime.Now;
                foreach (PC_list x in WokenPcs)
                {
                    if (x.ip == Ipadd)
                    {
                        x.time = addingtime;
                        exists = false;
                    }
                }
                if (exists)
                {
                    PC_list listObject = new PC_list();
                    listObject.PcName = PcName;
                    listObject.NickName = nickname;
                    listObject.ip = Ipadd;
                    listObject.status = status;
                    listObject.time = addingtime;
                    WokenPcs.Add(listObject);
                }
            }
        }

        public string ipaddress_ipv4()
        {
            IPHostEntry host;
            string localIP = "?";
            host = Dns.GetHostEntry(Dns.GetHostName());
            foreach (IPAddress ip in host.AddressList)
            {
                if (ip.AddressFamily.ToString() == "InterNetwork")
                {
                    localIP = ip.ToString();
                }
            }
            return localIP;
        }
        #endregion MscFunc

        #region TCPconnection
        #endregion TCPconnection

        #endregion MyCode

        private void Form_MainWindow_Resize(object sender, EventArgs e)
        {
            
        }

        private void connectToolStripMenuItem_Click(object sender, EventArgs e)
        {
            button_Connect_Click(sender, e);
        }

        private void Form_MainWindow_FormClosed(object sender, FormClosedEventArgs e)
        {

        }

        private void Form_MainWindow_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (e.CloseReason == CloseReason.UserClosing)
            {
                e.Cancel = true;
                this.Visible = false;
                notifyIcon_InLAN.ShowBalloonTip(3000);
            }
        }

        private void notifyIcon_InLAN_DoubleClick(object sender, EventArgs e)
        {
            this.Visible = true;
            this.WindowState = FormWindowState.Normal;
        }

        private void exitToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            exitToolStripMenuItem_Click( sender,  e);
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (StartServer != null && StartClient != null)
            {
                StartServer.Abort();
                StartClient.Abort();
                threadstop = false;
            }
            Application.Exit();
        }

        private void textBox_NickName_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
        {

        }

        private void textBox_NickName_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar == 13)
            {
                button_Connect_Click(sender, e);
            }
        }

        private void button_Connect_Click(object sender, EventArgs e)
        {
            this.label_NickName.Visible = false;
            this.textBox_NickName.Visible = false;
            this.button_Connect.Visible = false;
            disconnectToolStripMenuItem1.Enabled = true;
            disconnectToolStripMenuItem.Enabled = true;
            connectToolStripMenuItem.Enabled = false;
            connectToolStripMenuItem1.Enabled = false;
            

            this.listBox_MainList.Visible = true;

            threadstop = true;

            StartServer = new Thread(new ThreadStart(this.UdpServerFunc));
            StartClient = new Thread(new ThreadStart(this.UdpClientFunc));
            StartServer.Start();
            StartClient.Start();
        }

        private void Form_MainWindow_Load(object sender, EventArgs e)
        {
            this.listBox_MainList.Visible = false;
            this.toolStripStatusLabel_StatusMainWindow.Text = "Status: Disconnected";
            this.disconnectToolStripMenuItem.Enabled = false;
            disconnectToolStripMenuItem1.Enabled = false;
        }

        private void listBox_MainList_DoubleClick(object sender, EventArgs e)
        {
            ArrayList tempform = new ArrayList();
            foreach (Form_ChatWindow x in OpenChatWindows)
            {
                if (x.server_GotClient == null && x.server_socket == null && x.client_GotServer == null && x.client_socket == null)
                {
                    tempform.Add(x);
                }
            }
            foreach (Form_ChatWindow x in tempform)
            {
                OpenChatWindows.Remove(x);
            }


            string Smessage = null;
            byte[] Bmessage = new byte[100];
            string whichip = null;
            string whichNickName = null;
            string pcname = Dns.GetHostName();
            string[] ChatStarter = new string[2];
            ChatStarter = (this.listBox_MainList.SelectedItem.ToString()).Split(' ');

            foreach (Form_ChatWindow x in OpenChatWindows)
            {
                if (x.nickname == ChatStarter[0])
                {
                    x.Visible = true;
                    return;
                }
            }

            foreach (PC_list x in WokenPcs)
            {
                if (x.NickName == ChatStarter[0] && ("(" + x.PcName + ")" == ChatStarter[1]))
                {
                    whichip = x.ip;
                    whichNickName = ChatStarter[0];
                }
            }

            Smessage = "BlueBall [OpenChat]:" + pcname + ":" + ipaddress_ipv4() + ":Available:" + this.textBox_NickName.Text + ":" + PortNum.ToString() + ":";
            Bmessage = Encoding.ASCII.GetBytes(Smessage);

            IPEndPoint chatpoint_endpoint = new IPEndPoint(IPAddress.Parse(whichip), 9050);
            EndPoint ChatPointEndPoint = (EndPoint)chatpoint_endpoint;
            UdpClient.SendTo(Bmessage, Bmessage.Length,SocketFlags.None, chatpoint_endpoint);
            Form_ChatWindow newchat = new Form_ChatWindow(whichip, PortNum, whichNickName, true);
            newchat.Text = "InLAN Chat Messenger: " + whichNickName;
            OpenChatWindows.Add(newchat);
            newchat.Show();
            PortNum = PortNum + 1;
        }

        private void disconnectToolStripMenuItem_Click(object sender, EventArgs e)
        {
            disconnectToolStripMenuItem.Enabled = false;
            disconnectToolStripMenuItem1.Enabled = false;
            connectToolStripMenuItem1.Enabled = true;
            connectToolStripMenuItem.Enabled = true;
            listBox_MainList.Visible = false;
            label_NickName.Visible = true;
            button_Connect.Visible = true;
            textBox_NickName.Visible = true;
            this.toolStripStatusLabel_StatusMainWindow.Text = "Status: Disconnected";

            threadstop = false;

            StartServer.Abort();
            StartClient.Abort();
            
        }

        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            AboutBox about = new AboutBox();
            about.Show();
        }

        private void startAtStartupToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (startAtStartupToolStripMenuItem.Checked.Equals(true) == true)
            {
                //MessageBox.Show("Startup Path: " + Application.StartupPath);
                CreateStartupFolderShortcut();
                startAtStartupToolStripMenuItem.Checked.Equals(false);
            }

            if (startAtStartupToolStripMenuItem.Checked.Equals(false) == true)
            {
                //MessageBox.Show("Executable Path: " + Application.ExecutablePath);
                DeleteStartupFolderShortcuts("InLAN.exe");
                startAtStartupToolStripMenuItem.Checked.Equals(true);
            }
        }

        private void connectToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            button_Connect_Click(sender, e);
        }

        private void disconnectToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            disconnectToolStripMenuItem_Click( sender,  e);
        }

        private void inLANChatMessengerToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Visible = true;
        }

        private void cannotSeeOtherPCsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            MessageBox.Show("If you cannot see other online PCs, you might have following problems:\n" +
                "1. Firewall might be blocking.\n" +
                "2. You might have more than one network interfaces (This happens when you install VMware).",
                "Cannot find PCs in my Network...");

        }
    }

    public class PC_list
    {
        //I am Alive:pcname:myip:NickName:time
        public string PcName;
        public string ip;
        public string status;
        public string NickName;
        public DateTime time;

        public string ThisToString()
        {
            string temp;
            temp = NickName + " (" + PcName + ")";
            return temp;
        }
    }
}
